<script lang="ts" setup>
import type { ShopGoodsApi } from '#/api/shop/goods';

import { computed, onMounted, ref, watch, defineExpose } from 'vue';
import { Select as ASelect } from 'ant-design-vue';

import { getGoodsPage } from '#/api/shop/goods';

interface OptionItem {
  value: number | string;
  label: string;
  cover: string;
  price?: number | null;
  stock?: number | null;
  typeName?: string | null;
  goodsName: string;
}

defineOptions({name: 'goods-binder'})

const props = defineProps<{
  // 兼容 v-model:value 与 v-model:modelValue（表单引擎默认使用 value）
  value?: any;
  modelValue?: any;
  placeholder?: string;
  disabled?: boolean;
}>();
const emit = defineEmits<{
  (e: 'update:modelValue', v: any): void;
  (e: 'update:value', v: any): void;
  (e: 'change', payload: { ids: Array<number | string>; info: any[] }): void;
  (e: 'update:goodsInfo', v: Array<any>): void; // 兼容旧用法
}>();

const loading = ref(false);
const keyword = ref('');
const options = ref<OptionItem[]>([]);
const selected = ref<Array<{ label: string; value: number | string }>>([]);
const isLoaded = ref(false);
const pendingOuterValue = ref<any>(null);

function withImgPrefix(path: string) {
  if (!path) return '';
  if (/^https?:\/\//i.test(path) || /^\/shop-img-api\//.test(path)) return path;
  return `/shop-img-api/${path.replace(/^\/+/, '')}`;
}

async function loadOptions() {
  loading.value = true;
  try {
    const resp = await getGoodsPage({ page: 1, limit: 50, goods_name: keyword.value, status: 1 });
    const list: any[] = Array.isArray((resp as any)?.data)
      ? (resp as any).data
      : Array.isArray((resp as any)?.list)
      ? (resp as any).list
      : [];
    options.value = list.map((item: any) => {
      const cover = withImgPrefix(item?.goods_cover_thumb_small || item?.goods_cover || '');
      return {
        value: item.goods_id,
        label: item.goods_name,
        goodsName: item.goods_name,
        cover,
        price: item?.goodsSku?.price ?? null,
        stock: item?.stock ?? null,
        typeName: item?.goods_type_name ?? null,
      } as OptionItem;
    });
  } finally {
    loading.value = false;
    isLoaded.value = true;
    if (pendingOuterValue.value !== null) {
      const normalized = normalizeToSelected(pendingOuterValue.value);
      ensureOptionsForSelected(normalized, pendingOuterValue.value);
      selected.value = normalized;
      pendingOuterValue.value = null;
    }
  }
}

function onSearch(val: string) {
  keyword.value = val;
  loadOptions();
}

function emitComposite(val: Array<{ label: string; value: number | string }>) {
  const map = new Map(options.value.map((o) => [o.value, o]));
  const ids = (val || []).map((v) => v.value);
  const infos = (val || []).map((v) => {
    const found = map.get(v.value);
    if (found) {
      return {
        goodsId: found.value,
        goodsName: found.goodsName,
        price: found.price,
        stock: found.stock,
        goodsTypeName: found.typeName,
        cover: found.cover,
      };
    }
    return { goodsId: v.value, goodsName: v.label };
  });
  // 表单字段多为单值绑定，此处将字段值更新为 info 数组，确保 vxe 能拿到
  emit('update:modelValue', infos);
  emit('update:value', infos);
  // 同时提供完整变更事件，便于外部同步 goodsIdss
  emit('change', { ids, info: infos });
  emit('update:goodsInfo', infos);
}

function onUpdate(val: Array<{ label: string; value: number | string }>) {
  selected.value = val;
  emitComposite(val);
}

onMounted(async () => {
  await loadOptions();
  // 初次加载后，应用外部值
  const initial = outerValue.value;
  if (initial !== undefined) {
    const normalized = normalizeToSelected(initial);
    ensureOptionsForSelected(normalized, initial);
    selected.value = normalized;
  }
});

// 将外部传入的值规范化为 labelInValue 数组
function normalizeToSelected(input: any): Array<{ label: string; value: number | string }> {
  const normalizeId = (id: any) => {
    const n = Number(id);
    return Number.isNaN(n) ? id : n;
  };
  if (!input) return [];
  // 优先兼容复合对象的 info（仅回显 goodsInfo 的场景）
  if (Array.isArray((input as any).info) && (input as any).info.length > 0) {
    const info: any[] = (input as any).info;
    return info.map((item: any) => {
      const v = normalizeId(item?.goodsId);
      return { value: v, label: item?.goodsName ?? String(v) };
    });
  }
  // 复合对象 { ids, info }
  if (Array.isArray(input.ids)) {
    const ids: any[] = input.ids;
    const info: any[] = Array.isArray(input.info) ? input.info : [];
    return ids.map((id, idx) => {
      const v = normalizeId(id);
      return { value: v, label: info[idx]?.goodsName ?? String(v) };
    });
  }
  // 已是 labelInValue 数组
  if (Array.isArray(input)) {
    if (input.length === 0) return [];
    // 对象数组（详情对象）
    if (typeof input[0] === 'object' && 'goodsId' in input[0]) {
      return (input as any[]).map((item: any) => {
        const v = normalizeId(item.goodsId);
        return { value: v, label: item.goodsName ?? String(v) };
      });
    }
    // 已是 labelInValue 数组
    if (typeof input[0] === 'object' && 'value' in input[0]) {
      return (input as any[]).map((o: any) => ({ value: normalizeId(o.value), label: o.label }));
    }
    // 只是 id 数组
    return (input as any[]).map((id) => {
      const v = normalizeId(id);
      return { value: v, label: String(v) };
    });
  }
  return [];
}

// 同步 props 到内部选中值
const outerValue = computed(() => props.modelValue ?? props.value);
watch(
  outerValue,
  async (v) => {
    if (!isLoaded.value) {
      pendingOuterValue.value = v;
      return;
    }
    const normalized = normalizeToSelected(v);
    ensureOptionsForSelected(normalized, v);
    selected.value = normalized;
  },
  { immediate: true },
);

// 确保下拉选项包含被选中的 value（编辑回显时可能后端传回的商品不在当前页数据里）
function ensureOptionsForSelected(
  normalizedSelected: Array<{ label: string; value: number | string }>,
  sourceInput: any,
) {
  const map = new Map(options.value.map((o) => [o.value, o]));
  // 构建 info 索引
  let infoMap = new Map<any, any>();
  if (Array.isArray(sourceInput) && sourceInput.length && typeof sourceInput[0] === 'object' && 'goodsId' in sourceInput[0]) {
    infoMap = new Map((sourceInput as any[]).map((it: any) => [Number(it.goodsId) || it.goodsId, it]));
  } else if (sourceInput && Array.isArray(sourceInput.info)) {
    infoMap = new Map((sourceInput.info as any[]).map((it: any) => [Number(it.goodsId) || it.goodsId, it]));
  }
  const merged: OptionItem[] = [...options.value];
  for (const sel of normalizedSelected) {
    if (!map.has(sel.value)) {
      const extra = infoMap.get(sel.value) || {};
      merged.push({
        value: sel.value,
        label: sel.label,
        goodsName: extra.goodsName || sel.label,
        cover: withImgPrefix(extra.cover || ''),
        price: extra.price ?? null,
        stock: extra.stock ?? null,
        typeName: extra.goodsTypeName ?? null,
      });
      map.set(sel.value, true as any);
    }
  }
  options.value = merged;
}

// 根据已加载的选项查找封面
function getCoverByValue(val: number | string) {
  const found = options.value.find((o) => o.value === val);
  return withImgPrefix(found?.cover || '');
}

// 暴露方法，便于表单引擎编程式设置与获取
defineExpose({
  setValue(v: any) {
    selected.value = normalizeToSelected(v);
  },
  getValue() {
    // 返回 info 对象数组，保持与字段值一致
    const map = new Map(options.value.map((o) => [o.value, o]));
    return (selected.value || []).map((v: any) => {
      const found = map.get(v.value);
      if (found) {
        return {
          goodsId: found.value,
          goodsName: found.goodsName,
          price: found.price,
          stock: found.stock,
          goodsTypeName: found.typeName,
        };
      }
      return { goodsId: v.value, goodsName: v.label };
    });
  },
  reset() {
    selected.value = [];
  },
});
</script>

<template>
  <ASelect
    v-model:value="selected"
    @update:value="onUpdate"
    mode="multiple"
    label-in-value
    show-search
    :filter-option="false"
    :loading="loading"
    @search="onSearch"
    style="width: 100%"
    :placeholder="placeholder || '请选择需要绑定的商品'"
    :disabled="disabled"
  >
    <template #tagRender="{ value, label, closable, onClose }">
      <div class="ant-select-selection-item" :title="label">
        <img :src="getCoverByValue(value)" alt="" style="width:16px;height:16px;object-fit:cover;border-radius:2px;margin-right:6px;background:#f5f5f5;" />
        <span>{{ label }}</span>
        <span v-if="closable" class="ant-select-selection-item-remove" @mousedown.prevent @click.stop="onClose">×</span>
      </div>
    </template>
    <ASelect.Option
      v-for="opt in options"
      :key="opt.value"
      :value="opt.value"
      :label="opt.goodsName"
    >
      <div style="display:flex;align-items:center;gap:8px;white-space:nowrap;min-width:0;">
        <img :src="opt.cover" :alt="opt.goodsName" style="width:24px;height:24px;object-fit:cover;border-radius:4px;flex:none;background:#f5f5f5;" />
        <span style="display:inline-block;min-width:0;">
          {{ opt.goodsName }} ｜ ¥{{ opt.price ?? 0 }} ｜ 库存{{ opt.stock ?? 0 }} ｜ {{ opt.typeName ?? '' }}
        </span>
      </div>
    </ASelect.Option>
  </ASelect>

</template>


